/**
 * @file STL_HttpServer.cpp
 * @author Derek Liu (yjkhtddx@sina.com)
 * @brief 
 * @version 0.1
 * @date 2021-02-07
 * 
 * @copyright Copyright Sci-Tech Laboratories (c) 2021
 * 
 */

#include "STL_HttpServer.h"
#include <sys/epoll.h>
#include "STL_Tools.h"
#include "STLOG.h"
#include "STL_TcpServer.h"
#include "STL_Text.h"
#include "STL_URL.h"

#define EPOLL_MAX_EVENTS 10 // 单次处理事件个数

namespace STL
{
    STL_HttpServer::STL_HttpServer(HttpServerConfig config) : m_config(config)
    {
        STL_TcpServer::TcpServerConfig tcpConfig(config.ip, config.port);
        m_tcpServer = new STL_TcpServer(tcpConfig);
        m_tcpServer->setConnectCallback([=](int socket, std::string ip, uint16_t port) {
            if (m_handlerMap.count(socket) == 1)
            {
                stlog_warn("ERROR, Invalid socket");
                m_handlerMap.erase(socket); // 假设socket存在,删除已存在的socket,（正常情况此调用不会无效）
            }
            m_handlerMap[socket] = std::shared_ptr<STL_HttpParser>(new STL_HttpParser(socket));
            m_handlerMap[socket]->setRequestCallback(STL_CALLBACK_2(STL_HttpServer::handler, this));
        });
        m_tcpServer->setDisconnectCallback([=](int socket) {
            if (m_handlerMap.count(socket) == 1)
            {
                m_handlerMap.erase(socket);
            }
        });
        m_tcpServer->setDataCallback([=](int socket, std::shared_ptr<std::string> sp_data) {
            if (m_handlerMap.count(socket) == 1)
            {
                m_handlerMap[socket]->addData(sp_data);
            }
            else
            {
                stlog_error("unhandled http data：%s\n", sp_data->c_str());
            }
        });
        m_tcpServer->startListen();
    }

    STL_HttpServer::~STL_HttpServer()
    {
        m_handlerMap.clear();
        STL_SAFE_DELETE(m_tcpServer);
    }

    void STL_HttpServer::handler(int socketId, std::shared_ptr<STL_HttpRequest> req)
    {
        // stlog_debug("STL_HttpServer::handler[%s]", req->m_path.c_str());
        std::shared_ptr<STL_HttpResponse> res(new STL_HttpResponse());
        std::string path = getHandlerPath(req->m_path);
        if (m_handlers.count(path) != 1)
        {
            res->setCode(404);
            std::string msg = res->genHttpMessage();
            m_tcpServer->sendData(socketId, msg);
        }
        else
        {
            m_handlers[path](req, res, [this, socketId, res]() {
                std::string msg = res->genHttpMessage();
                m_tcpServer->sendData(socketId, msg);
                m_tcpServer->closeSocket(socketId);
            });
        }
    }

} // namespace STL